package cn.ibizlab.util.security;

import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.RSADecrypter;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jose.jwk.RSAKey;
import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.util.io.pem.PemObject;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.crypto.Cipher;
import java.io.File;
import java.io.FileInputStream;
import java.io.StringWriter;
import java.security.PrivateKey;

@Component
public class JwkStore {

    JwkStore getSelf() {
        return SpringContextHolder.getBean(this.getClass());
    }


    private RSAKey rsaKey;

    private RSAKey publicJWK;

    private PrivateKey privateKey;

    private JWSVerifier verifier;

    private Cipher rsaCipher;

    /**
     * 获取密钥文件
     * @return
     * @throws Exception
     */
    @SneakyThrows
    @CacheEvict(value = "ibzuaa_signaturekey")
    public synchronized RSAKey getRSAKeyFile(){
        if(rsaKey == null) {
            String strPSAKey;
            String userHome = System.getProperty("user.home") + "/.ibzrt";
            File rsaKeyFile = new File(userHome, "keystore.jwks");

            if (!rsaKeyFile.exists())
                strPSAKey = IOUtils.toString(this.getClass().getResourceAsStream("/keypair/keystore.jwks"), "UTF-8");
            else
                strPSAKey = IOUtils.toString(new FileInputStream(rsaKeyFile), "UTF-8");

            if (ObjectUtils.isEmpty(strPSAKey)) {
                throw new RuntimeException(String.format("系统未配置密钥信息[%1$s]", rsaKeyFile.getPath()));
            }

            rsaKey = RSAKey.parse(strPSAKey);
        }
        return rsaKey;
    }

    public RSAKey getPublicJWK() {
        if (publicJWK == null)
            publicJWK = getSelf().getRSAKeyFile().toPublicJWK();
        return publicJWK;
    }

    @SneakyThrows
    public PrivateKey getPrivateKey() {
        if (privateKey == null)
            privateKey = getSelf().getRSAKeyFile().toPrivateKey();
        return privateKey;
    }

    private RSADecrypter rsaDecrypter;
    @SneakyThrows
    public RSADecrypter getRSADecrypter() {
        if (rsaDecrypter == null) {
            if (privateKey == null)
                privateKey = getSelf().getRSAKeyFile().toPrivateKey();
            rsaDecrypter = new RSADecrypter(privateKey);
        }
        return rsaDecrypter;
    }

    @SneakyThrows
    public JWSVerifier getJWSVerifier() {
        if (verifier == null)
            verifier = new RSASSAVerifier(getPublicJWK());
        return verifier;
    }

    @SneakyThrows
    public Cipher getRsaCipher() {
        if(rsaCipher == null){
            rsaCipher = Cipher.getInstance("RSA");
            rsaCipher.init(Cipher.DECRYPT_MODE, getPrivateKey());
        }
        return rsaCipher;
    }

    private String publicKeyPem;

    @SneakyThrows
    public String getPublicKeyPem() {
        if (publicKeyPem == null) {
            JcaPEMWriter pemWriter = null;
            StringWriter stringWriter = new StringWriter();
            try {

                pemWriter = new JcaPEMWriter(stringWriter);
                pemWriter.writeObject(new PemObject("PUBLIC KEY", getSelf().getPublicJWK().toPublicKey().getEncoded()));

            }catch (Exception ex) {
                publicKeyPem = "";
            }
            finally {
                if(pemWriter != null)
                    try {
                        pemWriter.close();
                        publicKeyPem = stringWriter.toString();
                    }catch (Exception ex) {
                        publicKeyPem = "";
                    }
            }
        }
        return publicKeyPem;
    }
}
